#ifndef _VERTEX_BUFFER_H_
#define _VERTEX_BUFFER_H_

#include <windows.h>
#include <d3d9.h>
#include "Vertices.h"
#include "Globals.h"

namespace Cartesia
{

//-----------------------------------------------------------------------

template <class VertexFormat, unsigned int FVF>
class VertexBuffer
{
public:
	unsigned int			_VBSize;
	unsigned int			_flush;
	unsigned int			_base;
	unsigned int			_vertexToLock;
	D3DPRIMITIVETYPE 		_primitiveType;
	LPDIRECT3DVERTEXBUFFER9	_pVertexBuffer;
	IDirect3DDevice9		*_pDevice;

	bool Create(IDirect3DDevice9 * pDevice, bool dinamic);
	void Release(void);
	void Draw(VertexFormat * pVertexCollection, D3DPRIMITIVETYPE primitive, unsigned int vertexCount);
	void Flush();
	void Bind();

};

//-----------------------------------------------------------------------

template <class VertexFormat, unsigned int FVF>
bool VertexBuffer<VertexFormat, FVF>::Create(IDirect3DDevice9 * pDevice, bool dinamic)
{
	_VBSize = 450;
	_flush = 150;

	static HRESULT hr;

	if (!pDevice)
		return false;
	else
		_pDevice = pDevice;

	hr = _pDevice->CreateVertexBuffer(
		_VBSize*sizeof(VertexFormat), 
		(dinamic ? D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC : 0),
		D3DFVF_XYZ,
		D3DPOOL_DEFAULT,
		&_pVertexBuffer,
		0
		);

	return (hr == D3D_OK);
}

//-----------------------------------------------------------------------

template <class VertexFormat, unsigned int FVF>
void VertexBuffer<VertexFormat, FVF>::Draw(VertexFormat *pVertexCollection, D3DPRIMITIVETYPE primitive, unsigned int vertexCount)
{

	static void			*pVertices;
	static unsigned int vertexProcessNow;

	vertexProcessNow = 0;

	_primitiveType = primitive;

	if (_flush< vertexCount)
		_vertexToLock = _flush;
	else
		_vertexToLock = vertexCount;

	if (_base + _vertexToLock > _VBSize)
		_base = 0;

	static HRESULT hr;

	// base el offset, donde empieza a leer
	hr = _pVertexBuffer->Lock(
		_base * sizeof(VertexFormat),
		_vertexToLock * sizeof (VertexFormat),
		(void**) &pVertices, 
		_base ? D3DLOCK_NOOVERWRITE: D3DLOCK_DISCARD
		);

	while (_vertexToLock > 0)	{
		memcpy(
			pVertices, 
			&pVertexCollection[vertexProcessNow], 
			sizeof(VertexFormat) * _vertexToLock
			); 

		vertexProcessNow += _vertexToLock;

		hr = _pVertexBuffer->Unlock();

		Flush();

		_base += _vertexToLock;

		_vertexToLock = (_flush < (vertexCount - vertexProcessNow) ? _flush : vertexCount - vertexProcessNow);

		if (_base + _vertexToLock > _VBSize)
			_base = 0;

		hr = _pVertexBuffer->Lock(
			_base * sizeof(VertexFormat),
			_vertexToLock * sizeof(VertexFormat),
			(void**) &pVertices, 
			_base ? D3DLOCK_NOOVERWRITE: D3DLOCK_DISCARD
			);

	}		

	_pVertexBuffer->Unlock();

}

//-----------------------------------------------------------------------

template <class VertexFormat, unsigned int FVF>
void VertexBuffer<VertexFormat, FVF>::Flush()
{
	static unsigned int iPrimitiveCount;

	if (_primitiveType == D3DPT_POINTLIST)
		iPrimitiveCount = _vertexToLock;
	else if (_primitiveType == D3DPT_LINELIST)
		iPrimitiveCount = _vertexToLock/2;
	else if (_primitiveType == D3DPT_LINESTRIP)
		iPrimitiveCount = _vertexToLock-1;
	else if (_primitiveType == D3DPT_TRIANGLELIST)
		iPrimitiveCount = _vertexToLock/3;
	else if (_primitiveType == D3DPT_TRIANGLESTRIP)
		iPrimitiveCount = _vertexToLock-2;
	else
		iPrimitiveCount = 0;

	static HRESULT hr;
	hr = _pDevice->DrawPrimitive(_primitiveType, _base, iPrimitiveCount);
}

//-----------------------------------------------------------------------

template <class VertexFormat, unsigned int FVF>
void VertexBuffer<VertexFormat, FVF>::Release()
{

}

//-----------------------------------------------------------------------

template <class VertexFormat, unsigned int FVF>
void VertexBuffer<VertexFormat, FVF>::Bind()
{
//	_pDevice->SetVertexShader(NULL);
	_pDevice->SetFVF(FVF);
	_pDevice->SetStreamSource(0, _pVertexBuffer, 0, sizeof(VertexFormat));
}

//-----------------------------------------------------------------------

} // end namespace Cartesia

#endif //_VERTEX_BUFFER_H_